const { src, dest, series, parallel, watch } = require('gulp')

const sass = require('node-sass')

const browserSync = require('browser-sync').create()

// 自动加载所有插件
const plugins = require('gulp-load-plugins')()

// 默认配置
let config = {
  src: 'src',
  dist: 'dist',
  temp: '.temp',
  public: 'public',
  fonts: 'src/assets/fonts/**',
  images: 'src/assets/images/**',
  data: {}
}

try {
  const userConfig = require('./gulp.config.js')
  config = { ...config, ...userConfig }
} catch{ }

const clean = () => {
  return src([config.temp, config.dist], { read: false })
    .pipe(plugins.clean())
}

// 编译 sass 文件
const styles = () => {
  return src(`${config.src}/**/*.scss`, { base: config.src })
    .pipe(plugins.sass({ compiler: sass }))
    .pipe(dest(config.temp))
}

// 转换 ES6
const scripts = () => {
  return src(`${config.src}/**/*.js`, { base: config.src })
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest(config.temp))
}

// 编译 HTML 中的 Swig
const pages = () => {
  return src(`${config.src}/**/*.html`, { base: config.src })
    .pipe(plugins.swig({ data: config.data, defaults: { cache: false } }))
    .pipe(dest(config.temp))
}

// 打包引用模块，压缩 html css js
const useref = () => {
  return src(`${config.temp}/**/*.html`, { base: config.temp })
    .pipe(plugins.useref({ searchPath: [config.temp, '.'] }))   // 将 HTML 中引用的模块组合打包到一个文件，并替换路径
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({ collapseWhitespace: true, minifyCSS: true, minifyJS: true })))    // 压缩 html
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))   // 压缩 css
    .pipe(plugins.if(/\.js$/, plugins.uglify()))    // 压缩 js
    .pipe(dest(config.dist))
}

// 压缩图片及拷贝字体
const imagemin = () => {
  return src([config.images, config.fonts], { base: config.src })
    .pipe(plugins.imagemin())
    .pipe(dest(config.dist))
}

// 拷贝public
const copy = () => {
  return src(`${config.public}/**`, { base: config.public })
    .pipe(dest(config.dist))
}


// 浏览器热更新服务
const serve = () => {
  // 监听文件变化并自动执行构建任务
  // ignoreInitial: false 初始化时就执行
  watch(`${config.src}/**/ *.scss`, { ignoreInitial: false }, styles)
  watch(`${config.src}/**/ *.js`, { ignoreInitial: false }, scripts)
  watch(`${config.src}/**/ *.html`, { ignoreInitial: false }, pages)

  browserSync.init({
    // 文件改变将触发 reload
    files: [config.temp, config.public, config.images, config.fonts],
    // 监听的事件，触发这些事件将 reload
    watchEvents: ['add', 'change', 'unlink', 'addDir', 'unlinkDir'],
    server: {
      // 按顺序寻找用到的文件
      baseDir: [config.temp, config.src, config.public],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 编译 sass ES6 HTML 的异步组合任务
const compile = parallel(styles, scripts, pages)

// 打包
const build = parallel(series(compile, useref), imagemin, copy)

module.exports = {
  clean,
  serve,
  build
}